#pragma once
#include <cstdint>
#include <stdlib.h>
#include <cstring>
#include <vector>
#include "ai_common.h"
#define CIM_ROW  14
#define CIM_COL  4
#define MAX_OUT_NUM  64
namespace cim_tools {
    struct LayerConfig
    {
        uint8_t  shift_num;

        MatrixS8 input;
        MatrixS8 weight;
        VectorUS32 _input;
        VectorUS32 _weight;
        MatrixS8 output;
        uint64_t    BASE_IN_ADDR; 
        uint64_t    BASE_WT_ADDR;
        uint64_t    BASE_RS_ADDR;
        
        uint32_t cfg_cim_wet_num = 7168; // num of 128bit: 14*4*(16*128)*8 / 128 = 7168
        std::vector<uint32_t> inst_wt; // Instruction buffer
        std::vector<uint32_t> inst_run; // Instruction buffer
        std::vector<uint32_t> inst_input_dma;
        std::vector<uint32_t> inst_singlerun;
        std::vector<uint32_t> inst_output_dma;

        void wt_inst_gen();
        void run_inst_gen();
        void single_run_inst_gen();
        // Random Data Generator
        void data_rand_generator();
    };


    struct CIM_offline_utils {

        // Struct of CFG PARAM 
        LayerConfig layer_config;
        
        // Instruction Generator
        void run(const char * _save_path);

    };

    // 按pt_reg.h顺序定义APB寄存器结构体
    struct apb_regs_block {
        uint32_t TOP_AI_CHOOSE;                  // 0x00
        uint32_t RESERVED0[15];                  // 0x04 ~ 0x3C (填充到0x40)
        uint32_t CIM_ROW_CONFIG_BITS_0;          // 0x40
        uint32_t CIM_ROW_CONFIG_BITS_1;          // 0x44
        uint32_t CIM_ROW_CONFIG_BITS_2;          // 0x48
        uint32_t CIM_ROW_CONFIG_BITS_3;          // 0x4C
        uint32_t CIM_ROW_CONFIG_BITS_4;          // 0x50
        uint32_t CIM_ROW_CONFIG_BITS_5;          // 0x54
        uint32_t CIM_ROW_CONFIG_BITS_6;          // 0x58
        uint32_t CIM_ROW_CONFIG_BITS_7;          // 0x5C
        uint32_t CIM_ROW_CONFIG_BITS_8;          // 0x60
        uint32_t CIM_ROW_CONFIG_BITS_9;          // 0x64
        uint32_t CIM_ROW_CONFIG_BITS_10;         // 0x68
        uint32_t CIM_ROW_CONFIG_BITS_11;         // 0x6C
        uint32_t CIM_ROW_CONFIG_BITS_12;         // 0x70
        uint32_t CIM_ROW_CONFIG_BITS_13;         // 0x74
        uint32_t CIM_ROW_CONFIG_BITS_14;         // 0x78
        uint32_t CIM_ROW_CONFIG_BITS_15;         // 0x7C
        uint32_t CIM_TOP_START;                  // 0x80
        uint32_t CIM_CFG_CIM_DMA_MODE;           // 0x84
        uint32_t CIM_CFG_CIM_WT_MODE;            // 0x88
        uint32_t CIM_CFG_CIM_RELU_ENABLE;        // 0x8C
        uint32_t CIM_SHIFT_NUM;                  // 0x90
        uint32_t CIM_IN_NUM;                     // 0x94
        uint32_t CIM_CFG_TRANSFER_MODE;          // 0x98
        uint32_t CIM_CFG_RAM_START_ADDR;         // 0x9C
        uint32_t CIM_CIM_AXI_START_ADDR_32;      // 0xA0
        uint32_t CIM_AXI_START_ADDR_40;          // 0xA4
        uint32_t CIM_TRANSFER_NUM;               // 0xA8
        uint32_t CIM_CFG_TOP_FINISH;             // 0xAC
        uint32_t CIM_CFG_FINISH_CLR;             // 0xB0
        uint32_t CIM_CFG_CIM_PE_ENABLE0_31;      // 0xB4
        uint32_t CIM_CFG_CIM_PE_ENABLE32_63;     // 0xB8
        // 如有更多寄存器可继续补充
    };


    struct CIM_online_utils {
        // Basic PARAM
        uint64_t  DDR_BASE_ADDR = 0x95000000;
        // Struct of CFG PARAM 
        LayerConfig layer_config;
        // SRAM空间映射指针
        volatile uint32_t* dma_inst;
        // DDR空间映射指针
        volatile uint32_t* ddrbuf;
        // APB寄存器空间映射指针，类型为结构体指针
        volatile apb_regs_block* apb_regs;

        // 初始化
        int devmem_fd; // /dev/mem 文件描述符
        void pmem_mmap_init();
        void cfg_init();
        void wt_init();
        void run(const char * _save_path);
        void step_run(const char * _save_path);
        void act_transfer(const MatrixS8 input, VectorUS32 &_input);
        void wet_transfer(const MatrixS8 weight, VectorUS32 &_weight);
  
    };
}